/**
 * 
 */
package com.gr.staffpm.widget.calendar;

import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.RepeatingView;

import com.gr.menuw.horizontal.dropdown.multilevel.MultiLevelMenu;
import com.gr.menuw.menu.item.AjaxLinkMenuItem;
import com.gr.staffpm.gof.observer.Subscribable;
import com.gr.staffpm.gof.observer.Subscriber;
import com.gr.staffpm.widget.calendar.event.EventPanel;
import com.gr.staffpm.widget.calendar.model.AjaxChangeCalendarViewLink;
import com.gr.staffpm.widget.calendar.model.CalendarIterButton;
import com.gr.staffpm.widget.calendar.model.MonthLabelModel;
import com.gr.staffpm.widget.calendar.model.Views;


/**
 * @author Graham Rhodes 6 Jan 2011 12:21:17
 */
public class Calendar extends Panel implements IHeaderContributor, Subscriber {

    private static final long serialVersionUID = 1L;
    private final boolean includeWeekends = true;
    private final boolean weekStartMonday = true;
    private final java.util.Calendar cal = java.util.Calendar.getInstance();
    private static Double monthRowCurrentTop = 0.0;
    private static Double monthRowHeight;
    private MultiLevelMenu calendarMenu;
    private final WebMarkupContainer eventContainer, dayView;
    private final RepeatingView monthRows, dayNamesTable;
    private final Label monthName;
    private final EventPanel dayEventPanel;
    private Views view = Views.MONTH;

    public Calendar(String id) {
        super(id);

        add(new CalendarIterButton("prev", this, -1));
        add(new CalendarIterButton("next", this, 1));

        monthName = new Label("monthName", new MonthLabelModel(cal));
        monthName.setOutputMarkupId(true);
        add(monthName);
        add(buildCalendarMenu());

        //Create day of week headers


        eventContainer = (WebMarkupContainer) new WebMarkupContainer("eventContainer").setOutputMarkupId(true);
        dayNamesTable = (RepeatingView) new RepeatingView("dayNamesTable").setOutputMarkupId(true);
        dayView = (WebMarkupContainer) new WebMarkupContainer("dayView").setOutputMarkupId(true);
        monthRows = (RepeatingView) new RepeatingView("monthRows").setOutputMarkupId(true);
        dayEventPanel = (EventPanel) new EventPanel("dayEvents", cal, "cal-day-events").setOutputMarkupId(true);

        eventContainer.add(dayNamesTable);

        updateView();

        eventContainer.add(dayEventPanel);
        eventContainer.add(dayView);
        eventContainer.add(monthRows);
        add(eventContainer);
    }

    /**
     * @return
     */
    private List<String> getWeekdaysInOrder() {
        List<String> weekDays = new ArrayList<String>();
        weekDays.addAll(Arrays.asList(new DateFormatSymbols().getShortWeekdays()));
        weekDays = weekDays.subList(1, weekDays.size());
        if (weekStartMonday) {
            //If the week doesn't start with MONDAY then remove SUNDAY from the front
            //remove Sunday from the front of the list and add it to the end
            String sunday = weekDays.remove(0);
            weekDays.add(sunday);
            if (!includeWeekends) {
                weekDays.remove(6);//Remove SUNDAY which is now last in the list
                weekDays.remove(5);//Remove SATURDAY which is now last in the list
            }
        } else {
            if (!includeWeekends) {
                weekDays.remove(0);//Remove SUNDAY which is first in the list
                weekDays.remove(5);//Remove SATURDAY which is last in the list
            }
        }
        return weekDays;
    }

    private void updateDayView() {

        String dayName = cal.getDisplayName(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.LONG, getLocale());
        dayNamesTable.addOrReplace(new Label("1", dayName + " " + cal.get(java.util.Calendar.DAY_OF_MONTH)));

        dayEventPanel.setCal(cal);
        dayEventPanel.renderTasks();

        monthRowHeight = 100.0 / 24;

        RepeatingView dayEvents = new RepeatingView("dayEvents");
        for (int time = 0; time < 24; time++) {
            dayEvents.addOrReplace(new DayRow(String.valueOf(time)).setOutputMarkupId(true));
        }
        RepeatingView dayTimes = new RepeatingView("dayTimes");
        for (int time = 0; time < 24; time++) {
            String timeLabel = String.valueOf((time % 12 == 0 ? 12 : time % 12)) + (time >= 12 ? " pm" : " am");
            dayTimes.addOrReplace(new DayTimeRow(String.valueOf(time), timeLabel));
        }

        dayView.addOrReplace(dayEvents);
        dayView.addOrReplace(dayTimes);
    }

    private void updateMonthView() {

        List<String> weekDays = getWeekdaysInOrder();
        for (String dayName : weekDays) {
            dayNamesTable.addOrReplace(new Label(String.valueOf(weekDays.indexOf(dayName)), dayName));
        }

        //Add rows of weeks in month with respect to the calendar and week in month we're working with
        cal.set(java.util.Calendar.DATE, 1);

        int firstWeekdayOfMonth = cal.get(java.util.Calendar.DAY_OF_WEEK);
        if (weekStartMonday && firstWeekdayOfMonth != 1)
            firstWeekdayOfMonth -= 1;
        else if (firstWeekdayOfMonth == 1)
            firstWeekdayOfMonth = 7;

        int weeksInMonth = ((firstWeekdayOfMonth + this.cal.getActualMaximum(java.util.Calendar.DAY_OF_MONTH) + 5) / 7);
        int month = cal.get(java.util.Calendar.MONTH);

        int date = 1 - (firstWeekdayOfMonth - 1);
        monthRowHeight = 100.0 / weeksInMonth;

        java.util.Calendar calRef = java.util.Calendar.getInstance();
        calRef.setTime(cal.getTime());

        monthRows.removeAll();
        for (int i = 1; i <= weeksInMonth; i++) {
            calRef.set(java.util.Calendar.DATE, date);
            monthRows.addOrReplace(new MonthRow(String.valueOf(i), calRef, month).setOutputMarkupId(true));
            date += 7;
        }
        monthRowCurrentTop = 0.0;
    }

    private MultiLevelMenu buildCalendarMenu() {
        calendarMenu = new MultiLevelMenu("calendar-menu");
        calendarMenu.setOutputMarkupId(true);
        calendarMenu.setRenderBodyOnly(false);

        AjaxChangeCalendarViewLink dayViewLink = new AjaxChangeCalendarViewLink("link", this, AjaxChangeCalendarViewLink.DAY_VIEW_SIGNAL);
        calendarMenu.addItem(new AjaxLinkMenuItem("1", "Day", dayViewLink));

        AjaxChangeCalendarViewLink weekViewLink = new AjaxChangeCalendarViewLink("link", this, AjaxChangeCalendarViewLink.WEEK_VIEW_SIGNAL);
        calendarMenu.addItem(new AjaxLinkMenuItem("2", "Week", weekViewLink));

        AjaxChangeCalendarViewLink monthViewLink = new AjaxChangeCalendarViewLink("link", this, AjaxChangeCalendarViewLink.MONTH_VIEW_SIGNAL);
        calendarMenu.addItem(new AjaxLinkMenuItem("3", "Month", monthViewLink));

        return calendarMenu;
    }

    /* (non-Javadoc)
     * @see org.apache.wicket.markup.html.IHeaderContributor#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
     */
    @Override
    public void renderHead(IHeaderResponse response) {
        response.renderCSSReference(new ResourceReference(Calendar.class, "css/calendar.css"));
    }


    public static Double getMonthRowCurrentTop() {
        return monthRowCurrentTop;
    }


    public static void setMonthRowCurrentTop(Double monthRowCurrentTop) {
        Calendar.monthRowCurrentTop = monthRowCurrentTop;
    }

    public static Double getMonthRowHeight() {
        return monthRowHeight;
    }


    public boolean isIncludeWeekends() {
        return includeWeekends;
    }


    public boolean isWeekStartMonday() {
        return weekStartMonday;
    }


    public java.util.Calendar getCal() {
        return cal;
    }


    public Label getMonthName() {
        return monthName;
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.subscriber.ISubscriber#subscribeTo(com.gr.staffpm.gof.observer.subscribable.ISubscribable)
     */
    @Override
    public void subscribeTo(Subscribable subscribable) {
    }

    /* (non-Javadoc)
     * @see com.gr.staffpm.gof.observer.subscriber.ISubscriber#notifySubscriber(java.lang.Object, org.apache.wicket.ajax.AjaxRequestTarget)
     */
    @Override
    public void notifySubscriber(Object obj, AjaxRequestTarget target) {
        if (obj.equals(AjaxChangeCalendarViewLink.DAY_VIEW_SIGNAL)) {
            view = Views.DAY;
        } else if (obj.equals(AjaxChangeCalendarViewLink.WEEK_VIEW_SIGNAL)) {
            view = Views.WEEK;
        } else if (obj.equals(AjaxChangeCalendarViewLink.MONTH_VIEW_SIGNAL)) {
            view = Views.MONTH;
        }
        target.addComponent(eventContainer);
        target.addComponent(monthName);
        updateView();
    }

    public void updateView() {

        dayNamesTable.removeAll();
        dayView.setVisible(view.equals(Views.DAY));
        dayEventPanel.setVisible(view.equals(Views.DAY));
        monthRows.setVisible(view.equals(Views.MONTH));

        if (view.equals(Views.DAY)) {
            updateDayView();
        } else if (view.equals(Views.MONTH)) {
            updateMonthView();
        }
    }

    public WebMarkupContainer getEventContainer() {
        return eventContainer;
    }

    public void setView(Views view) {
        this.view = view;
    }

    public Views getView() {
        return view;
    }

    public RepeatingView getMonthRows() {
        return monthRows;
    }


    public WebMarkupContainer getDayRows() {
        return dayView;
    }


    public RepeatingView getDayNamesTable() {
        return dayNamesTable;
    }

}
